/*
 * @Author       : borfish
 * @Date         : 2025-08-07 16:45:44
 * @LastEditors  : borfish
 * @LastEditTime : 2025-08-11 17:01:32
 * @FilePath     : /src/MqttHandler.cpp
 * @Description  : 
 * Copyright 2025 OBKoro1, All Rights Reserved. 
 * 2025-08-07 16:45:44
 */

 #include "include/MqttHandler.h"
 #include <QDebug>
 #include <QTimer>

 /**
  * @func: MQTTManager类的构造函数
  * @description: 初始化MQTT客户端对象，并建立所有必要的信号与槽连接
  * @param {QObject} *parent    父对象指针，用于Qt的对象树管理
  * @return {*}
  * @example: 
  */ 
 MQTTHandler::MQTTHandler(QObject *parent)
    : QObject(parent)
{
    // 创建QMqttClient实例，将当前对象作为其父对象
    m_client_ = new QMqttClient(this);

    // 连接信号槽
    connect(m_client_, &QMqttClient::connected, this, &MQTTHandler::onConnected);
    connect(m_client_, &QMqttClient::disconnected, this, &MQTTHandler::onDisconnected);
    connect(m_client_, &QMqttClient::errorChanged, this, [this](QMqttClient::ClientError error){
        onError(error);
    });
    connect(m_client_, &QMqttClient::messageReceived, this, &MQTTHandler::onMessageReceived);
}

 /**
  * @func: 连接到MQTT代理服务器
  * @description: 该方法会先验证输入参数的有效性，然后配置客户端并尝试连接到指定的MQTT代理
  * @param {QString} &host      代理服务器主机地址（IP或域名）
  * @param {quint16} port       代理服务器端口号（通常为1883）
  * @param {QString} &username  登录用户名（可选）
  * @param {QString} &password  登录密码（可选）
  * @return {*}
  * @example: 
  */
void MQTTHandler::connectToBroker(const QString &host, quint16 port,
                                const QString &username , const QString &password)
{
    if(host.isEmpty()) {
        emit connectionError("主机地址不能为空");
        return;
    }

    if(port <= 0 || port > 65535) {
        emit connectionError("无效的端口号");
        return;
    }

    m_client_->setHostname(host);
    m_client_->setPort(port);

    if(!username.isEmpty()) {
        m_client_->setUsername(username);
    }

    if(!password.isEmpty()) {
        m_client_->setPassword(password);
    }

    emit logMessage(QString("正在连接到MQTT代理: %1:%2").arg(host).arg(port));
    m_client_->connectToHost();
}
/**
 * @func: 断开与MQTT代理服务器的连接
 * @description: 仅当客户端处于连接状态时才执行断开连接操作
 * @return {*}
 * @example: 
 */
void MQTTHandler::disconnectFromBroker()
{
    if(m_client_->state() == QMqttClient::Connected) {
        emit logMessage("正在断开MQTT连接...");
        m_client_->disconnectFromHost();
    }
}

/**
 * @func: 发布消息到指定的MQTT主题
 * @description: 该方法会先检查连接状态和主题有效性，然后发布消息并发送相关信号
 * @param {QString} &topic      消息要发布到的主题
 * @param {QString} &message    要发布的消息内容
 * @param {quint8} qos          服务质量等级（0-2），决定消息传递的可靠性
 * @return {*}
 * @example: 
 */
void MQTTHandler::publish(const QString &topic, const QString &message,quint8 qos)
{
    // 检查是否已连接到MQTT代理
    if(m_client_->state() != QMqttClient::Connected) {
        emit connectionError("未连接到MQTT代理");
        return;
    }

    if(topic.isEmpty()) {
        emit connectionError("发布主题不能为空");
        return;
    }

    // 创建MQTT主题对象     
    QMqttTopicName t(topic);
    // 验证主题是否有效
    if(t.isValid()) {
        m_client_->publish(t,message.toUtf8(), qos);
        emit messagePublished(topic, message);
        emit logMessage(QString("已发布消息 [主题: %1]: %2").arg(topic).arg(message));
    }else {
        emit connectionError("无效的主题格式: " + topic);
    }
}

/**
 * @func: 订阅指定的MQTT主题
 * @description: 订阅成功后，将接收该主题下的所有消息，并通过信号通知
 * @param {QString} &topic  要订阅的主题
 * @param {quint8} qos      服务质量等级，决定消息接收的可靠性
 * @return {*}
 * @example: 
 */
void MQTTHandler::subscribe(const QString &topic, quint8 qos)
{
    // 检查客户端是否已连接
    if(m_client_->state() != QMqttClient::Connected) {
        emit connectionError("未连接到MQTT代理");
        return;
    }

    if(topic.isEmpty()) {
        emit connectionError("发布主题不能为空");
        return;
    }

    
    // 订阅指定主题，返回订阅对象
    auto subsrciption = m_client_->subscribe(topic,qos);
    if(!subsrciption) {
        emit connectionError("订阅失败: " + topic);
        return;
    }

    // 连接信号槽：当订阅对象收到消息时，转发消息到自定义信号
    connect(subsrciption,&QMqttSubscription::messageReceived,
        this, [this,topic](QMqttMessage msg){
            onMessageReceived(msg.payload(), msg.topic());
        });

    // 发送订阅成功的信号
    emit subscribed(topic);
    emit logMessage("已订阅主题: " + topic);
}
/**
 * @func: 取消订阅指定的MQTT主题
 * @description: 取消后将不再接收该主题下的消息
 * @param {QString} &topic  要取消订阅的主题
 * @return {*}
 * @example: 
 */
void MQTTHandler::unsubscribe(const QString &topic)
{
// 检查客户端是否已连接
    if(m_client_->state() != QMqttClient::Connected) {
        emit connectionError("未连接到MQTT代理");
        return;
    }

    if(topic.isEmpty()) {
        emit connectionError("发布主题不能为空");
        return;
    }

    m_client_->unsubscribe(topic);
    emit unsubscribed(topic);
    emit logMessage("已取消订阅主题: " + topic);
}


/**
 * @func: 检查客户端是否已连接到broker
 * @description: 
 * @return {*}如果已连接返回true，否则返回false
 * @example: 
 */
bool MQTTHandler::isConnected() const{
    return m_client_->state() == QMqttClient::Connected;
}
/**
 * @func:   获取当前客户端的连接状态
 * @description:获取当前客户端的连接状态
 * @return {*}
 * @example: 
 */
QMqttClient::ClientState MQTTHandler::connectionState() const
{
    return m_client_->state();
}

/**
 * @func: 处理连接成功事件
 * @description: 当客户端成功连接到MQTT代理后，发送连接成功的信号和日志
 * @return {*}
 * @example: 
 */
void MQTTHandler::onConnected()
{
    emit connected();
    emit logMessage("已成功连接到MQTT代理");
}


/**
 * @func: 处理断开连接事件
 * @description: 当客户端与MQTT代理断开连接后，发送断开连接的信号和日志
 * @return {*}
 * @example: 
 */
void MQTTHandler::onDisconnected()
{
    emit disconnected();
    emit logMessage("已断开MQTT连接");
}
/**
 * @func: 处理MQTT客户端错误
 * @description: 将错误代码转换为可读的错误消息并发送状态通知
 * @param {ClientError} error   错误代码，来自QMqttClient::ClientError枚举
 * @return {*}
 * @example: 
 */
void MQTTHandler::onError(QMqttClient::ClientError error)
{
    QString errorMsg;
    switch (error)
    {
        case QMqttClient::InvalidProtocolVersion: errorMsg = "无效的协议版本"; break;
        case QMqttClient::IdRejected: errorMsg = "客户端ID被拒绝"; break;
        case QMqttClient::ServerUnavailable: errorMsg = "服务器不可用"; break;
        case QMqttClient::BadUsernameOrPassword: errorMsg = "用户名或密码错误"; break;
        case QMqttClient::NotAuthorized: errorMsg = "未授权"; break;
        case QMqttClient::TransportInvalid: errorMsg = "传输无效"; break;
        case QMqttClient::ProtocolViolation: errorMsg = "协议违规"; break;
        case QMqttClient::UnknownError: errorMsg = "未知错误"; break;
        default: errorMsg = "未定义错误"; break;
    }
    // 保存最后一次错误信息，并发送错误信号和日志
    m_lastError_ = errorMsg;
    emit connectionError(errorMsg);
    emit logMessage("MQTT错误: " + errorMsg);
}
/**
 * @func: 处理接收到的MQTT消息
 * @description: 将接收到的消息转换为QString并通过信号转发
 * @param {QByteArray} &message     消息内容（原始字节数组）
 * @param {QMqttTopicName} &topic   消息所在的主题
 * @return {*}
 * @example: 
 */
void MQTTHandler::onMessageReceived(const QByteArray &message, const QMqttTopicName &topic)
{
    QString msg = QString::fromUtf8(message);
    // 发送消息接收信号，包含主题和消息内容
    emit messageReceived(topic.name(), msg);
    emit logMessage(QString("收到消息 [主题: %1]: %2").arg(topic.name()).arg(msg));
}